package org.wattdepot.gdata.kukuicup;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * Provides a wrapper around the GData properties file in order to perform error checking and 
 * to provide convenient access to properties and their default values. 
 * @author Philip Johnson
 */
public class GDataProperties {
  
  /** Holds the properties instance constructed from the properties file. */
  private Properties properties = new Properties();
  
  /**
   * Create a new GDataProperties instance given the passed file name, signaling errors if 
   * the properties file cannot be found or if problems occur during loading. 
   * Writes output indicating the status of the initialization. 
   * @param fileName The file name of the properties file.
   * @throws RuntimeException If properties file cannot be found. 
   */
  public GDataProperties(String fileName) {
    String filePath = System.getProperty("user.home") + "/.wattdepot/client/";
    File propertiesFile = new File(filePath, fileName);
    if (propertiesFile.exists()) {
      System.out.println("Reading properties from: " + propertiesFile.toString());
    }
    else {
      String msg = "Properties file not found: " + propertiesFile.toString();
      System.out.println(msg);
      throw new RuntimeException(msg);
    }
    // Now load the properties. 
    FileInputStream stream = null;
    try {
      stream = new FileInputStream(propertiesFile); 
      this.properties.load(stream);
    }
    catch (Exception e) {
      System.out.format("Fatal error loading properties: " + e.getMessage());
      throw new RuntimeException(e);
    }
    finally {
      try {
        stream.close();
      }
      catch (IOException e) {
        System.out.println("Could not close stream associated with properties file.");
      }
    }
  }
  
  /**
   * The default version of GDataProperties that looks for "kukuicup.gdata.properties". 
   * Used mainly for testing. 
   */
  public GDataProperties() {
    this("kukuicup.gdata.properties");
  }
  
  /**
   * Return the Google Authentication token from the properties file, or null if not found.
   * @return The authentication token, or null.
   */
  public String getToken() {
    return properties.getProperty("google.authentication.token");
  }
  

  /**
   * Returns the WattDepot server URI, or throws a Runtime exception if not found.
   * @return The WattDepot URI.
   * @throws RuntimeException If not found. 
   */
  public String getWattDepotUri() {
    return getRequiredProperty("wattdepot-server.uri");
  }

  /**
   * Returns the GData user name, or throws a Runtime exception if not found.
   * @return The GData user name.
   * @throws RuntimeException If not found. 
   */
  public String getGDataUserName() {
    return getRequiredProperty("gdata.username");
  }

  /**
   * Returns the GData password, or throws a Runtime exception if not found.
   * @return The GData password
   * @throws RuntimeException If not found. 
   */
  public String getGDataPassword() {
    return getRequiredProperty("gdata.password");
  }

  
  /**
   * Returns the value of the passed property name, or throws a Runtime exception if not found.
   * @param propName The property name.
   * @return The property value. 
   * @throws RuntimeException If not found. 
   */
  public String getRequiredProperty(String propName) {
    String propValue = this.properties.getProperty(propName, null);
    // Abort if not present.
    if (propValue == null) {
      String msg = "Fatal error: required property not found: " + propName;
      System.out.println(msg);
      throw new RuntimeException(msg);
    }
    return propValue;
  }
  
  /**
   * Returns the value associated with the passed property, or null if not found.
   * @param propName The property of interest.
   * @return The value, or null.
   */
  public String getProperty(String propName) {
    return this.properties.getProperty(propName, null);
  }
  
  /**
   * Returns the value associated with the passed property, or the default if not found.
   * @param propName The property of interest.
   * @param defaultValue The value to return if the property is not present.
   * @return The value, or null.
   */
  public String getProperty(String propName, String defaultValue) {
    return this.properties.getProperty(propName, defaultValue);
  }
  
  /**
   * Returns the value of propName as an integer. 
   * If propName is not present or cannot be parsed, will return the default value.
   * @param propName The property name.
   * @param defaultValue The value to be used if we cannot get an integer for this property name.
   * @return The value as an integer.
   */
  public int getIntegerProperty(String propName, int defaultValue) {
    int propValue = 0;
    try {
      propValue = Integer.valueOf(this.properties.getProperty(propName));
    }
    catch (Exception e) {
      propValue = defaultValue;
    }
    return propValue;
  }
  
  /**
   * Constructs and returns a list of updater class names that are enabled in this property file.
   * @return The list of enabled updater class names. 
   */
  public List<String> getEnabledUpdaterClassNames() {
    List<String> enabledUpdaters = new ArrayList<String>();
    for (GDataUpdater property : GDataUpdater.values()) {
      if (isEnabled(property)) {
        enabledUpdaters.add(property.getUpdater());
      }
    }
    return enabledUpdaters;
  }
  
  /**
   * Returns true if the specified updater is enabled in the properties file. 
   * @param property The updater property.
   * @return True if enabled. 
   */
  private boolean isEnabled(GDataUpdater property) {
    String value = this.properties.getProperty(property.getKey(), "false");
    return (value.equalsIgnoreCase("true"));
  }
  
  /**
   * An enumerated type that specifies all of the updater properties in the GData properties
   * file, and the GData updater class associated with it. 
   * @author Philip Johnson
   */
  public enum GDataUpdater {
    
    /** The power meter updater.*/
    POWER_METER("power.meter.enabled",
    "org.wattdepot.gdata.kukuicup.updater.powermeter.PowerMeterUpdater"), 
  
    /** The daily energy baseline updater.*/
    DAILY_ENERGY_BASELINES("daily.energy.baselines.enabled", 
    "org.wattdepot.gdata.kukuicup.updater.energybaselines.DailyEnergyBaselinesUpdater"), 

    /** The daily energy baseline updater.*/
    HOURLY_ENERGY_BASELINES("hourly.energy.baselines.enabled", 
    "org.wattdepot.gdata.kukuicup.updater.energybaselines.HourlyEnergyBaselinesUpdater"), 
    
    /** The energy miniview updater.*/
    ENERGY_MINIVIEW("energy.miniview.enabled", 
    "org.wattdepot.gdata.kukuicup.updater.energyminiview.EnergyMiniViewUpdater"), 

    /** The energy last 24 hrs. updater.*/
    ENERGY_LAST_TWENTY_FOUR_HOURS("energy.last.twenty.four.hours.enabled",
    "org.wattdepot.gdata.kukuicup.updater.energylasttwentyfourhours." + 
    "EnergyLastTwentyFourHoursUpdater"), 

    /** The hot spot updater.*/
    HOT_SPOT("hot.spot.enabled",
    "org.wattdepot.gdata.kukuicup.updater.hotspot.HotSpotUpdater"), 
      
    /** The energy goal game updater.*/
    ENERGY_GOAL_GAME("energy.goal.game.enabled",
    "org.wattdepot.gdata.kukuicup.updater.energygoalgame.EnergyGoalGameUpdater"), 
    
    /** The energy goal game updater for the beta test.*/
    ENERGY_GOAL_GAME_BETA_EVAL("energy.goal.game.beta.eval.enabled",
    "org.wattdepot.gdata.kukuicup.updater.energygoalgame.EnergyGoalGameBetaEvalUpdater"), 

    /** The recent power updater.*/
    POWER_LAST_FEW_MINUTES("power.last.few.minutes.enabled",
    "org.wattdepot.gdata.kukuicup.updater.powerlastfewminutes.PowerLastFewMinutesUpdater"),
    
    /** The energy last 7 days updater.*/
    ENERGY_LAST_SEVEN_DAYS("energy.last.seven.days.enabled",
    "org.wattdepot.gdata.kukuicup.updater.energylastsevendays.EnergyLastSevenDaysUpdater"), 
    
    /** The energy last 30 days updater.*/
    ENERGY_LAST_THIRTY_DAYS("energy.last.thirty.days.enabled",
    "org.wattdepot.gdata.kukuicup.updater.energylastthirtydays.EnergyLastThirtyDaysUpdater");
    
    /**
     * Creates a new instance of this enumerated type with the specified properties. 
     * @param key The key in the properties file.
     * @param updaterClassName The fully qualified name of the updater.
     */
    GDataUpdater(String key, String updaterClassName) {
      this.key = key;
      this.updaterClassName = updaterClassName;
    }
    
    /** The property key. */
    private String key;
    /** The updater class name. */
    private String updaterClassName;

    /**
     * Returns the property key.
     * @return The key.
     */
    public String getKey() {
      return this.key;
    }
    
    /**
     * Returns the class name associated with this updater.
     * @return The class name.
     */
    public String getUpdater() {
      return this.updaterClassName;
    }
  }
}
